package com.demomaster.quickaccessibility.view.hierarchy;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.os.AsyncTask;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

import com.demomaster.quickaccessibility.R;
import com.demomaster.quickaccessibility.cache.AccessNodeCache;
import com.demomaster.quickaccessibility.model.QuickAccessibilityNodeInfo;
import com.demomaster.quickaccessibility.service.AccessibilityHelper;
import com.demomaster.quickaccessibility.service.QuickAccessibilityService;
import com.demomaster.quickcompat.util.DisplayUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * 视图结构显示控件
 */
public class HierarchyView extends View {

    private static final String TAG = "HierarchyView";

    public HierarchyView(Context context) {
        super(context);
        init();
    }

    public HierarchyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public HierarchyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public HierarchyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    OnTouchListener onTouchListener = new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            float x = event.getX();
            float y = event.getY();
            touchPointF = new PointF(x, y);
            List<AccessibilityNodeInfo> selectedNodeInfoList = findNodeInfoListByPosition((int) (x + screenlocation[0]), (int) (y + screenlocation[1]));
            if(selectedNodeInfoList!=null&&selectedNodeInfoList.size()>0) {
                // 按面积从小到大排序
                Collections.sort(selectedNodeInfoList, new Comparator<AccessibilityNodeInfo>() {
                    @Override
                    public int compare(AccessibilityNodeInfo nodeInfo1, AccessibilityNodeInfo nodeInfo2) {
                        Rect r1 = AccessibilityHelper.getBundsInScreen(nodeInfo1);
                        Rect r2 = AccessibilityHelper.getBundsInScreen(nodeInfo2);
                        int area1 = r1.width() * r1.height();
                        int area2 = r2.width() * r2.height();
                        return Integer.compare(area1, area2);
                    }
                });
                selectedNodeInfo = selectedNodeInfoList.get(0);
                // 使用 hitTest 方法查找触摸点所在的视图
                //AccessibilityNodeInfo touchedNode = QuickAccessibilityService.instance.getRootInActiveWindow().getHintText().hitTest(touchPoint);

                if (selectedNodeInfo != null) {
                    Log.d(TAG, "selectedNodeInfo=" + selectedNodeInfo);
                    if (event.getAction() == MotionEvent.ACTION_UP) {
                        if (onNodeInfoClickListener != null) {
                            //new RectF(x,y,getMeasuredWidth()-x,getMeasuredHeight()-y),
                            onNodeInfoClickListener.onClick(selectedNodeInfoList);
                        }
                    }
                }
            }
            invalidate();
            return true;
        }
    };

    PointF touchPointF;
    boolean isAccessibility;
    int screenWidth;
    int screenHeight;

    Paint paintRect;
    Paint paintRectSelected;
    Paint paintText;
    Paint paintTextBackground;
    Paint paintPoint;

    private void init() {
        accessNodeRectList = new ArrayList<>();
        paintRect = new Paint();
        paintRect.setStrokeWidth(2);
        paintRect.setColor(Color.RED);
        paintRect.setStyle(Paint.Style.STROKE);

        paintRectSelected = new Paint();
        paintRectSelected.setStrokeWidth(3);
        paintRectSelected.setColor(Color.GREEN);
        paintRectSelected.setStyle(Paint.Style.STROKE);

        paintPoint = new Paint();
        paintPoint.setColor(Color.YELLOW);
        int w2 = DisplayUtil.dip2px(getContext(), 2);
        paintPoint.setStrokeWidth(w2);

        paintText = new Paint();
        paintText.setXfermode(null);
        paintText.setStrokeWidth(1);
        paintText.setStyle(Paint.Style.FILL);
        paintText.setColor(Color.BLACK);

        paintTextBackground = new Paint();
        paintTextBackground.setColor(Color.BLACK);
        paintTextBackground.setStyle(Paint.Style.FILL);

        setOnTouchListener(onTouchListener);
        screenWidth = DisplayUtil.getScreenWidth(getContext());
        screenHeight = DisplayUtil.getScreenHeight(getContext());
    }

    /**
     * 获取最小的控件
     *
     * @param nodeInfoList
     * @return
     */
//    private QuickAccessibilityNodeInfo getMiniNodeInfo(List<QuickAccessibilityNodeInfo> nodeInfoList) {
//        QuickAccessibilityNodeInfo miniInfo = null;
//        if (nodeInfoList != null) {
//            for (QuickAccessibilityNodeInfo nodeInfo : nodeInfoList) {
//                if (miniInfo == null) {
//                    miniInfo = nodeInfo;
//                } else {
//                    if (accessNodeRectMap.containsKey(miniInfo.hashCode()) && accessNodeRectMap.containsKey(nodeInfo.hashCode())) {
//                        Rect rect = accessNodeRectMap.get(miniInfo.hashCode()).rect;
//                        Rect rect2 = accessNodeRectMap.get(nodeInfo.hashCode()).rect;
//                        if (rect2.width() * rect2.height() < rect.width() * rect.height()) {
//                            miniInfo = nodeInfo;
//                        }
//                    }
//                }
//            }
//        }
//        return miniInfo;
//    }

    AccessibilityNodeInfo selectedNodeInfo;//标记选择的控件

    public void setSelectedNodeInfo(AccessibilityNodeInfo selectedNodeInfo) {
        this.selectedNodeInfo = selectedNodeInfo;
        postInvalidate();
    }

    /**
     * 根据位置获取控件，存在叠加情况所以有可能得到多个结果
     *
     * @param x
     * @param y
     * @return
     */
    private List<AccessibilityNodeInfo> findNodeInfoListByPosition(int x, int y) {
        if (accessNodeRectList != null) {
            List<AccessibilityNodeInfo> nodeInfoList = new ArrayList<>();
            for (AccessibilityNodeInfo nodeInfo  : accessNodeRectList) {
                Rect rect = AccessibilityHelper.getBundsInScreen(nodeInfo);
                if (rect.contains(x, y)) {
                    if (nodeInfo != null) {
                        nodeInfoList.add(nodeInfo);
                    }
                }
            }
            return nodeInfoList;
        }
        return null;
    }

//    public AccessibilityNodeInfo findNodeAtPoint(AccessibilityNodeInfo root, int x, int y) {
//        if (root == null) {
//            return null;
//        }
//
//        Rect boundsInScreen = new Rect();
//        root.getBoundsInScreen(boundsInScreen);
//
//        // 检查根节点是否包含了给定的坐标
//        if (boundsInScreen.contains(x, y)) {
//            // 首先检查当前节点
//            if (isNodeAtPoint(root, x, y)) {
//                AccessibilityNodeInfo nodeInfo = root;
//                // 然后递归地检查子节点
//                for (int i = 0; i < root.getChildCount(); i++) {
//                    AccessibilityNodeInfo child = root.getChild(i);
//                    AccessibilityNodeInfo hitChild = findNodeAtPoint(child, x, y);
//                    if (hitChild != null) {
//                        //return hitChild;
//                        nodeInfo = hitChild;
//                    }
//                }
//                return nodeInfo;
//            }
//        }
//
//        return null;
//    }
//
//    private boolean isNodeAtPoint(AccessibilityNodeInfo node, int x, int y) {
//        Rect boundsInScreen = new Rect();
//        node.getBoundsInScreen(boundsInScreen);
//        return boundsInScreen.contains(x, y);
//    }

    public interface OnNodeInfoClickListener {
        //void onClick(QuickAccessibilityNodeInfo nodeInfo);

        void onClick(List<AccessibilityNodeInfo> nodeInfoList);
    }

    OnNodeInfoClickListener onNodeInfoClickListener;

    public void setOnNodeInfoClickListener(OnNodeInfoClickListener onNodeInfoClickListener) {
        this.onNodeInfoClickListener = onNodeInfoClickListener;
    }

    int[] screenlocation = null;

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        screenlocation = new int[2];
        getLocationOnScreen(screenlocation);//获取在整个屏幕内的绝对坐标
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        long t1 = System.currentTimeMillis();
        nodeCount = 0;
//        if (QuickAccessibilityService.instance.getQuickAccessNodeInfo() == null) {
//            return;
//        }
       // drawRectNode(canvas, QuickAccessibilityService.instance.getQuickAccessNodeInfo());
        drawRect(canvas);
        if (selectedNodeInfo != null) {
            Rect rect = AccessibilityHelper.getBundsInScreen(selectedNodeInfo);
            Rect rect1 = new Rect(rect.left - screenlocation[0], rect.top - screenlocation[1], rect.right - screenlocation[0], rect.bottom - screenlocation[1]);
            canvas.drawRect(rect1, paintRectSelected);
            String tip = rect1.width() + "x" + rect1.height();


            paintText.setTextSize(getContext().getResources().getDimensionPixelSize(R.dimen.quickdev_small_text_size));
            // 文字宽
            float textWidth = paintText.measureText(tip);
            // 文字baseline在y轴方向的位置
            float baseLineY = Math.abs(paintText.ascent() + paintText.descent()) / 2f;
            float left = rect1.left + (rect1.width() - textWidth) / 2;
            float top = rect1.bottom - baseLineY / 2f;
            paintText.setColor(Color.BLACK);
            paintText.setStyle(Paint.Style.FILL);

            Paint.FontMetrics fm = paintText.getFontMetrics();
            float height1 = fm.descent - fm.ascent;
            float lineHeight = fm.bottom - fm.top + fm.leading;
            float top1 = rect1.bottom - lineHeight;

            RectF rectF = new RectF(left, top1, left + textWidth, rect1.bottom);
            canvas.drawRect(rectF, paintTextBackground);
            paintText.setColor(Color.WHITE);
            canvas.drawText(tip, left, top, paintText);
        }

        if (touchPointF != null) {
            int w = DisplayUtil.dip2px(getContext(), 15);
            Shader mShader = new LinearGradient(touchPointF.x - w, touchPointF.y - w, touchPointF.x + w, touchPointF.y + w, new int[]{0xff000000, 0xffffffff}, null, Shader.TileMode.CLAMP);
//新建一个线性渐变，前两个参数是渐变开始的点坐标，第三四个参数是渐变结束的点的坐标。连接这2个点就拉出一条渐变线了，玩过PS的都懂。然后那个数组是渐变的颜色。下一个参数是渐变颜色的分布，如果为空，每个颜色就是均匀分布的。最后是模式，这里设置的是循环渐变
            paintPoint.setShader(mShader);
            canvas.drawLine(touchPointF.x - w, touchPointF.y, touchPointF.x + w, touchPointF.y, paintPoint);
            canvas.drawLine(touchPointF.x, touchPointF.y - w, touchPointF.x, touchPointF.y + w, paintPoint);
        }

        Log.d(TAG, "accessNodeRectList3 绘图用时：" + (System.currentTimeMillis() - t1));

    }

    int nodeCount;

    private void drawRectNode(Canvas canvas, QuickAccessibilityNodeInfo nodeInfo) {
        if (nodeInfo == null) {
            return;
        }
        long t1 = System.currentTimeMillis();
        Rect rect = nodeInfo.getBoundsInScreenRect();//节点范围
        //nodeInfo.getBoundsInScreen(rect);
        Rect rectScreen = new Rect(0, 0, screenWidth, screenHeight);//屏幕范围
        if (rectScreen.intersect(rect)) {//剔除掉非屏幕范围外的节点
            Rect rect1 = new Rect(rect.left - screenlocation[0], rect.top - screenlocation[1], rect.right - screenlocation[0], rect.bottom - screenlocation[1]);//在view树内的坐标
            canvas.drawRect(rect1, paintRect);
            //Log.d(TAG, "绘制第：" + nodeCount + "，用时：" + (System.currentTimeMillis() - t1));
            nodeCount += 1;
            for (int i = 0; i < nodeInfo.getChildCount(); i++) {
                long t2 = System.currentTimeMillis();
                QuickAccessibilityNodeInfo accessNodeInfo = nodeInfo.getChild(i);
                //Log.d(TAG, "获取第" + i + "个用时：" + (System.currentTimeMillis() - t2) + "," + accessNodeInfo);

                drawRectNode(canvas, accessNodeInfo);
            }
        }
    }

    private void drawRect(Canvas canvas) {
        for (AccessibilityNodeInfo accessNode : accessNodeRectList) {
            Rect accessNodeRect = AccessibilityHelper.getBundsInScreen(accessNode);
            Rect rect1 = new Rect(accessNodeRect.left - screenlocation[0], accessNodeRect.top - screenlocation[1], accessNodeRect.right - screenlocation[0], accessNodeRect.bottom - screenlocation[1]);
            canvas.drawRect(rect1, paintRect);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }

    //Map<Integer, RectNode> accessNodeRectMap = new HashMap<>();
    MyAsyncTask myAsyncTask;

    /**
     * 设置选中的控件
     *
     * @param accessibilityNodeInfo
     */
    private void setAccessibilityNodeInfo(AccessibilityNodeInfo accessibilityNodeInfo) {
        if (accessibilityNodeInfo != null) {
            isAccessibility = true;
            if (myAsyncTask != null && !myAsyncTask.isCancelled()) {
                myAsyncTask.cancel(true);
                myAsyncTask = null;
            }
            myAsyncTask = new MyAsyncTask();
            myAsyncTask.execute();
            //postInvalidate();
        }
    }

    public void updateAccessibilityNodeInfo() {
        //QuickAccessibilityNodeInfo rootInActiveWindow = QuickAccessibilityService.instance.getQuickAccessNodeInfo();//.getRootInActiveWindow();
        setAccessibilityNodeInfo(QuickAccessibilityService.instance.getRootInActiveWindow());
    }

    long time1 = 0;
    List<AccessibilityNodeInfo> accessNodeRectList;
    public class MyAsyncTask extends AsyncTask {

        @Override
        protected void onCancelled() {
            super.onCancelled();
        }

        @Override
        protected void onCancelled(Object o) {
            super.onCancelled(o);
        }

        @Override
        protected Object doInBackground(Object[] objects) {
            time1 = System.currentTimeMillis();
            //accessNodeRectMap.clear();
            //accessNodeMap.clear();
            //List<RectNode> accessNodeRectList2 = getNodeRect1();
            accessNodeRectList.clear();
            accessNodeRectList.addAll(AccessNodeCache.getInstance().getVisiableNodeList());
            Log.d(TAG, "accessNodeRectList2 用时2：" + (System.currentTimeMillis() - time1));
//            Log.d(TAG, "accessNodeRectList3 size=" + accessNodeRectList2.size() + ",用时：" + (System.currentTimeMillis() - time1));
            return null;
        }

        @Override
        protected void onPostExecute(Object o) {
            super.onPostExecute(o);
            //postInvalidate();
            invalidate();
        }
    }


}
